"""
    xfree.auth.services.password
    ~~~~~~~~~~~~~~~~~~~~~
    文件描述：密码重置管理器
    作者：xfree
    邮箱：cy_83k@qq.com
"""

from flask_babelplus import gettext as _

# 从相关模块导入ResetPasswordService（重命名为_ResetPasswordService）
from...core.auth.password import ResetPasswordService as _ResetPasswordService
from...core.exceptions import StopValidation, ValidationError
from...core.tokens import Token, TokenActions, TokenError
from xfree.utils.email import send_reset_token


class ResetPasswordService(_ResetPasswordService):
    """
    xfree的默认密码重置处理器，通过电子邮件管理密码重置过程。
    """

    def __init__(self, token_serializer, users, token_verifiers):
        """
        初始化方法

        :param token_serializer: 令牌序列化器
        :param users: 用户查询对象（可能与数据库查询相关）
        :param token_verifiers: 令牌验证器列表
        """
        self.token_serializer = token_serializer
        self.users = users
        self.token_verifiers = token_verifiers

    def initiate_password_reset(self, email):
        """
        发起密码重置操作

        :param email: 用户的电子邮件地址
        """
        # 根据电子邮件地址查询用户
        user = self.users.query.filter_by(email=email).first()

        if user is None:
            # 如果用户不存在，抛出验证错误
            raise ValidationError("email", _("Invalid email"))

        # 创建密码重置令牌
        token = self.token_serializer.dumps(
            Token(user_id=user.id, operation=TokenActions.RESET_PASSWORD)
        )

        # 异步发送密码重置令牌邮件
        send_reset_token.delay(token=token, username=user.username, email=user.email)

    def reset_password(self, token, email, new_password):
        """
        重置密码操作

        :param token: 密码重置令牌
        :param email: 用户的电子邮件地址
        :param new_password: 用户的新密码
        """
        # 反序列化令牌
        token = self.token_serializer.loads(token)
        if token.operation!= TokenActions.RESET_PASSWORD:
            # 如果令牌操作不是重置密码，抛出令牌错误
            raise TokenError.invalid()
        # 验证令牌
        self._verify_token(token, email)
        user = self.users.query.get(token.user_id)
        user.password = new_password

    def _verify_token(self, token, email):
        """
        验证令牌的方法

        :param token: 要验证的令牌
        :param email: 用户的电子邮件地址
        """
        errors = []

        for verifier in self.token_verifiers:
            try:
                verifier(token, email=email)
            except ValidationError as e:
                errors.append((e.attribute, e.reason))

        if errors:
            # 如果有验证错误，抛出停止验证异常
            raise StopValidation(errors)